﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web.Configuration;
using System.Web.Http;
using System.Web.Http.Controllers;
using Common.Logging;
using In.Api.Dto.HisWs;
using Newtonsoft.Json;
using OutDbContext;
using Rmq.Center;
using Senparc.Weixin.MP.TenPayLib;
using User.Api.BizExtensions;
using User.Api.Dto.Bill;
using User.Api.Helpers;
using User.Api.HttpClients;

namespace User.Api.Controllers
{
    public class BillController : ApiController
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(BillController));
        private FsssdqfybjyEntities _ctx;

        private static readonly object OrderNoLocker = new object();
        private static readonly object PayNotifyLocker = new object();

        private static TenPayInfo _tenPayInfo;

        public static TenPayInfo TenPayInfo
        {
            get
            {
                if (_tenPayInfo == null)
                {
                    _tenPayInfo =
                        TenPayInfoCollection.Data[ConfigurationManager.AppSettings["WeixinPay_PartnerId"]];
                }
                return _tenPayInfo;
            }
        }

        protected override void Initialize(HttpControllerContext controllerContext)
        {
            _ctx = new FsssdqfybjyEntities();
            base.Initialize(controllerContext);
        }

        protected override void Dispose(bool disposing)
        {
            _ctx.Dispose();
            base.Dispose(disposing);
        }

        /// <summary>
        /// 获取待缴费单列表
        /// </summary>
        /// <param name="cardId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetBillList")]
        public GetBillListResponse GetBillList(int cardId)
        {
            var azUser = AzUser.GetInApi(Request);

            var card = _ctx.HospCards.FirstOrDefault(x => x.Id == cardId && x.WxUserId == azUser.UserId);
            if (card == null)
            {
                return new GetBillListResponse
                {
                    ResultCode = "1",
                    ResultMsg = "找不到诊疗号信息"
                };
            }

            //获取院内webservice
            var request = new Request4GetClinRecipes();
            request.HosPatId = "";
            request.ClinNo = "";
            request.IdCard = "";
            request.CardNo = card.CardNo;
            request.DayCount = "30";

            Response4GetClinRecipes response;
            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/GetClinRecipes", request).Result;
                responseMsg.EnsureSuccessStatusCode();
                response = responseMsg.Content.ReadAsAsync<Response4GetClinRecipes>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内GetClinRecipes Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                return new GetBillListResponse
                {
                    ResultCode = "2",
                    ResultMsg = "服务器或网络异常，请联系客服！"
                };
            }

            if (response.ResultCode != "0")
            {
                return new GetBillListResponse
                {
                    ResultCode = "3",
                    ResultMsg = response.ResultDesc
                };
            }

            return new GetBillListResponse
            {
                ResultCode = "0",
                ResultMsg = "",
                Bills = response.ClinRecipeList
                    .Select(x => new GetBillListResponse.BillInfo
                    {
                        RecipeId = x.RecipeId,
                        FlowNo = x.FlowNo,
                        CardNo = x.CardNo,
                        PatientName = x.PatName,
                        CureDate = x.CureDate.ToDateTimeOrDefault().ToString("yyyy-MM-dd"),
                        DeptHisCode = x.DeptHisCode,
                        DeptName = x.DeptName,
                        DocHisCode = x.DocHisCode,
                        DocName = x.DocName,
                        PayType = x.PayType,
                        RecipeType = x.RecipeType,
                        TotalAmt = x.TotalAmt
                    }).ToList()
            };
        }


        /// <summary>
        /// 获得处方明细信息
        /// </summary>
        /// <param name="recipeId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetClinRecipeDetail")]
        public GetClinRecipeDetailResponse GetClinRecipeDetail(string recipeId)
        {
            var request = new Request4GetClinRecipeDetail();
            request.RecipeId = recipeId;

            Response4GetClinRecipeDetail response;
            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/GetClinRecipeDetail", request).Result;
                responseMsg.EnsureSuccessStatusCode();
                response = responseMsg.Content.ReadAsAsync<Response4GetClinRecipeDetail>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内GetClinRecipeDetail Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                return new GetClinRecipeDetailResponse
                {
                    ResultCode = "2",
                    ResultMsg = "服务器或网络异常，请联系客服！"
                };
            }

            if (response.ResultCode != "0")
            {
                return new GetClinRecipeDetailResponse
                {
                    ResultCode = "3",
                    ResultMsg = response.ResultDesc
                };
            }

            var clinRecipeDetailInfoList = response.ClinRecipeDetailList.Select(x => new GetClinRecipeDetailResponse.ClinRecipeDetailInfo
            {
                RecipeId = x.RecipeId,
                FeeName = x.FeeName,
                FeeCode = x.FeeCode,
                Unit = x.Unit,
                Spec = x.Spec,
                Price = ("0" + x.Price).ToDecimalOrDefault().ToString("F4"),
                Qty = x.Qty,
                Amt = ("0" + x.Amt).ToDecimalOrDefault().ToString("F4"),
                Sort = x.Sort,
                Remark = x.Remark
            }).ToList();

            return new GetClinRecipeDetailResponse()
            {
                ResultCode = "0",
                ResultMsg = "",
                ClinRecipeDetailInfos = clinRecipeDetailInfoList
            };
        }

        /// <summary>
        /// 生成缴费订单
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="selectedRecipeIds"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("CreateBillOrder")]
        public CreateBillOrderResponse CreateBillOrder(int cardId, string selectedRecipeIds)
        {
            var azUser = AzUser.GetInApi(Request);

            var card = _ctx.HospCards.FirstOrDefault(x => x.Id == cardId && x.WxUserId == azUser.UserId);
            if (card == null)
            {
                return new CreateBillOrderResponse
                {
                    ResultCode = "1",
                    ResultMsg = "找不到诊疗号信息"
                };
            }

            if (string.IsNullOrEmpty(selectedRecipeIds))
            {
                return new CreateBillOrderResponse
                {
                    ResultCode = "1",
                    ResultMsg = "没有选择需缴费的处方单"
                };
            }

            var cardNo = card.CardNo;
            ClinRecipeOrder clinRecipeOrder;

            using (var ctx = new FsssdqfybjyEntities())
            {
                //订单状态：0未支付 1支付中 2支付成功 3支付失败 4退款中 5退款成功 6退款失败 7缴费中 8缴费成功 9缴费失败
                //为了避免医生 在同一个 就诊流水号 上再次开单造成患者无法支付的情况，对于 未支付 和 缴费成功 的情况我们可以 再次生成订单
                clinRecipeOrder = ctx.ClinRecipeOrders.FirstOrDefault(x =>
                        x.CardNo == cardNo
                        && x.RecipeIds == selectedRecipeIds
                        //1:支付中
                        && (x.OrderStatus == 1
                        //2：支付成功
                        || x.OrderStatus == 2
                        //缴费中
                        || x.OrderStatus == 7));

                if (clinRecipeOrder != null)
                {
                    //未避免用户等待系统15分钟的情况出现
                    if (clinRecipeOrder.OrderStatus == 1)
                    {
                        clinRecipeOrder.OrderStatus = 9;
                        clinRecipeOrder.NextCheckTime = null;
                        clinRecipeOrder.OrderStatusOnSetCheck = null;

                        ctx.SaveChanges();
                    }
                    else
                    {
                        return new CreateBillOrderResponse
                        {
                            ResultCode = "3",
                            ResultMsg = "系统正在处理您的订单请耐心等候，大约需要15分钟"
                        };
                    }
                }
            }

            var request4GetClinRecipes = new Request4GetClinRecipes();
            request4GetClinRecipes.HosPatId = "";
            request4GetClinRecipes.ClinNo = "";
            request4GetClinRecipes.IdCard = "";
            request4GetClinRecipes.CardNo = card.CardNo;
            request4GetClinRecipes.DayCount = "30";

            Response4GetClinRecipes response4GetClinRecipes;
            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg4GetClinRecipes = httpClient.PostAsJsonAsync("HisWs/GetClinRecipes", request4GetClinRecipes).Result;
                responseMsg4GetClinRecipes.EnsureSuccessStatusCode();
                response4GetClinRecipes = responseMsg4GetClinRecipes.Content.ReadAsAsync<Response4GetClinRecipes>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内GetClinRecipes Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                return new CreateBillOrderResponse
                {
                    ResultCode = "2",
                    ResultMsg = "服务器或网络异常，请联系客服！"
                };
            }

            if (response4GetClinRecipes.ResultCode != "0")
            {
                return new CreateBillOrderResponse
                {
                    ResultCode = "3",
                    ResultMsg = response4GetClinRecipes.ResultDesc
                };
            }

            var selectedRecipeIdList = selectedRecipeIds.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            var selectedClinRecipeList =
                response4GetClinRecipes.ClinRecipeList.Where(x => selectedRecipeIdList.Contains(x.RecipeId)).ToList();


            var clinPayPrepareInfoList = new List<CreateBillOrderResponse.ClinPayPrepareInfo>();

            //是否全部都是自费的单据
            var isAllSelfPay = selectedClinRecipeList.All(x => x.PayType.IndexOf("自费", System.StringComparison.Ordinal) >= 0);
            //if (!isAllSelfPay)
            {
                //预结算处理获得支付金额
                var request4ClinPayPrepare = new Request4ClinPayPrepare();
                request4ClinPayPrepare.HosPatId = "";
                request4ClinPayPrepare.ClinNo = "";
                request4ClinPayPrepare.IdCard = "";
                request4ClinPayPrepare.CardNo = cardNo;
                request4ClinPayPrepare.RecipeIds = selectedRecipeIds;
                request4ClinPayPrepare.IsSb = isAllSelfPay ? "0" : "1";
                request4ClinPayPrepare.CashierId = "008886";
                request4ClinPayPrepare.MachineId = "008886";

                request4ClinPayPrepare.Request4ClinPayPrepareSubRecipeIdInfoList =
                    new List<Request4ClinPayPrepareSubRecipeIdInfo>();
                foreach (var selectedClinRecipe in selectedClinRecipeList)
                {
                    request4ClinPayPrepare.Request4ClinPayPrepareSubRecipeIdInfoList.Add(new Request4ClinPayPrepareSubRecipeIdInfo
                    {
                        FlowNo = selectedClinRecipe.FlowNo,
                        RecipeId = selectedClinRecipe.RecipeId,
                        PayType = selectedClinRecipe.PayType,
                    });
                }

                Response4ClinPayPrepare response4ClinPayPrepare;
                try
                {
                    var httpClient = InHttpClient.GetClient();
                    var responseMsg4ClinPayPrepare = httpClient.PostAsJsonAsync("HisWs/ClinPayPrepare", request4ClinPayPrepare).Result;
                    responseMsg4ClinPayPrepare.EnsureSuccessStatusCode();
                    response4ClinPayPrepare = responseMsg4ClinPayPrepare.Content.ReadAsAsync<Response4ClinPayPrepare>().Result;
                }
                catch (Exception ex)
                {
                    Logger.ErrorFormat("调用院内ClinPayPrepare Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                    return new CreateBillOrderResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "服务器或网络异常，请联系客服！"
                    };
                }

                if (response4ClinPayPrepare.ResultCode != "0")
                {
                    return new CreateBillOrderResponse
                    {
                        ResultCode = "3",
                        ResultMsg = response4ClinPayPrepare.ResultDesc
                    };
                }

                clinPayPrepareInfoList =
                    response4ClinPayPrepare.ClinPayPrepareList.Select(
                        x => new CreateBillOrderResponse.ClinPayPrepareInfo
                        {
                            FlowNo = x.FlowNo,
                            PatName = x.PatName,
                            DeptHisCode = x.DeptHisCode,
                            DeptName = x.DeptName,
                            DocHisCode = x.DocHisCode,
                            DocName = x.DocName,
                            RecipeId = x.RecipeId,
                            PayType = x.PayType,
                            TotalAmt = x.TotalAmt,
                            SelfAmt = x.SelfAmt,
                            SbPayAmt = x.SbPayAmt,
                        }).ToList();
            }

            using (var ctx = new FsssdqfybjyEntities())
            {
                var createBillOrderResponse = new CreateBillOrderResponse();

                float payAmt = 0;
                float selectedTotalAmt = 0;
                float selectedSelfAmt = 0;
                float selectedSbPayAmt = 0;
                if (clinPayPrepareInfoList.Count == 0)
                {
                    foreach (var item in selectedClinRecipeList)
                    {
                        payAmt += item.TotalAmt.ToSingleOrDefault();
                    }

                    createBillOrderResponse.SelectedTotalAmt = payAmt.ToString("F2");
                    createBillOrderResponse.SelectedSelfAmt = "";
                    createBillOrderResponse.SelectedSbPayAmt = "";
                }
                else
                {
                    foreach (var clinPayPrepareInfo in clinPayPrepareInfoList)
                    {
                        selectedTotalAmt += clinPayPrepareInfo.TotalAmt.ToSingleOrDefault();
                        selectedSelfAmt += clinPayPrepareInfo.SelfAmt.ToSingleOrDefault();
                        selectedSbPayAmt += clinPayPrepareInfo.SbPayAmt.ToSingleOrDefault();
                    }
                    payAmt = selectedSelfAmt;

                    createBillOrderResponse.SelectedTotalAmt = selectedTotalAmt.ToString("F2");
                    createBillOrderResponse.SelectedSelfAmt = selectedSelfAmt.ToString("F2");
                    createBillOrderResponse.SelectedSbPayAmt = selectedSbPayAmt.ToString("F2");
                }

                var newClinRecipeOrder = new ClinRecipeOrder
                {
                    WxUserId = azUser.UserId,
                    CardNo = cardNo,
                    PatName = card.PatientName,
                    RecipeIds = selectedRecipeIds,
                    OrderNo = GenerateNewOrderNo(),
                    IsSb = "0",
                    PayAmt = payAmt.ToString("F2"),
                    BankCardNo = "",
                    //PayDate = DateTime.Now,
                    CashierId = "008881",
                    MachineId = "008881",
                    OrderStatus = 0,
                    PayState = "0",
                    CreateTime = DateTime.Now
                };

                clinRecipeOrder = ctx.ClinRecipeOrders.Add(newClinRecipeOrder);
                ctx.SaveChanges();

                createBillOrderResponse.OrderId = clinRecipeOrder.Id;
                createBillOrderResponse.OrderNo = clinRecipeOrder.OrderNo;


                foreach (var item in selectedClinRecipeList)
                {
                    var clinPayPrepareInfo = clinPayPrepareInfoList.FirstOrDefault(x => x.RecipeId == item.RecipeId);
                    var clinRecipeOrderItem = new ClinRecipeOrderItem
                    {
                        ClinRecipeOrderId = clinRecipeOrder.Id,
                        CardNo = cardNo,
                        RecipeId = item.RecipeId,
                        FlowNo = item.FlowNo,
                        PatName = item.PatName,
                        CureDate = item.CureDate,
                        DeptHisCode = item.DeptHisCode,
                        DeptName = item.DeptName,
                        DocHisCode = item.DocHisCode,
                        DocName = item.DocName,
                        PayType = item.PayType,
                        RecipeType = item.RecipeType,
                        TotalAmt = clinPayPrepareInfo == null ? item.TotalAmt : clinPayPrepareInfo.TotalAmt,
                        SelfAmt = clinPayPrepareInfo == null ? "" : clinPayPrepareInfo.SelfAmt,
                        SbPayAmt = clinPayPrepareInfo == null ? "" : clinPayPrepareInfo.SbPayAmt,
                    };

                    createBillOrderResponse.ClinRecipeOrderItems.Add(new CreateBillOrderResponse.ClinRecipeOrderItem
                    {
                        CardNo = clinRecipeOrderItem.CardNo,
                        RecipeId = clinRecipeOrderItem.RecipeId,
                        FlowNo = clinRecipeOrderItem.FlowNo,
                        PatName = clinRecipeOrderItem.PatName,
                        CureDate = clinRecipeOrderItem.CureDate.ToDateTimeOrDefault().ToString("yyyy-MM-dd HH:mm"),
                        DeptHisCode = clinRecipeOrderItem.DeptHisCode,
                        DeptName = clinRecipeOrderItem.DeptName,
                        DocHisCode = clinRecipeOrderItem.DocHisCode,
                        DocName = clinRecipeOrderItem.DocName,
                        PayType = clinRecipeOrderItem.PayType,
                        RecipeType = clinRecipeOrderItem.RecipeType,
                        TotalAmt = clinRecipeOrderItem.TotalAmt,
                        SelfAmt = clinRecipeOrderItem.SelfAmt,
                        SbPayAmt = clinRecipeOrderItem.SbPayAmt,
                    });

                    ctx.ClinRecipeOrderItems.Add(clinRecipeOrderItem);
                }

                ctx.SaveChanges();

                createBillOrderResponse.ResultCode = "0";
                createBillOrderResponse.ResultMsg = "";
                return createBillOrderResponse;
            }
        }


        /// <summary>
        /// 支付缴费单
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("PayBill")]
        public PayBillReponse PayBill(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            var order = _ctx.ClinRecipeOrders.IsStatus(BillOrderExtensions.OrderStatus.未支付)
                .FirstOrDefault(x => x.Id == orderId && x.WxUserId == azUser.UserId);
            if (order == null)
            {
                return new PayBillReponse
                {
                    ResultCode = "1",
                    ResultMsg = "找不到缴费单"
                };
            }

            order.OrderStatus = BillOrderExtensions.OrderStatus.支付中.ToInt32();
            _ctx.SaveChanges();
            order.PayState = BillOrderExtensions.PayState.已付款.ToInt32().ToString();
            order.PayTime = DateTime.Now;
            order.WxTransactionId = "0";
            order.OrderStatus = BillOrderExtensions.OrderStatus.支付成功.ToInt32();
            _ctx.SaveChanges();

            // RMQ 执行取号
            var pickupingProducer = new OrderPickupingProducer();
            pickupingProducer.Publish(new OrderPickupingMsg
            {
                OrderType = OrderType.门诊缴费订单,
                OrderId = order.Id
            });

            return new PayBillReponse
            {
                ResultCode = "0",
                ResultMsg = "",
                PayString = "",
            };
            // RMQ 16分钟后如果还是支付中则设置支付失败
            var payingTimeoutProducer = new OrderPayingTimeoutProducer();
            payingTimeoutProducer.Publish(new OrderPayingTimeoutMsg
            {
                OrderType = OrderType.门诊缴费订单,
                OrderId = order.Id
            }, 16 * 60 * 1000);

            //组织 微信 js 支付方法 getBrandWCPayRequest 的参数
            var payStartTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
            var payExpireTime = System.DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");

            var payFee = (order.PayAmt.ToDecimalOrDefault() * 100).ToInt32().ToString();
            var superWxUserIds = ConfigurationManager.AppSettings["UserIdsForPayMin"].Split(" , ",
            StringSplitOptions.RemoveEmptyEntries);
            if (order.WxUserId.HasValue && superWxUserIds.Contains(order.WxUserId.ToStringOrDefault()))
            {
                payFee = "1";
            }

            var result = WeixinPayV3Helper.ComposeJsApiParameter("就诊缴费", "BL" + order.OrderNo,
                  payFee, GetClientIp(), payStartTime, payExpireTime, "Bill/PaySucceed", azUser.OpenId);

            if (result.ResultCode != "0")
            {
                return new PayBillReponse
                {
                    ResultCode = "1",
                    ResultMsg = result.ResultMsg
                };
            }

            return new PayBillReponse
            {
                ResultCode = "0",
                ResultMsg = "",
                PayString = result.Parameter
            };
        }

        /// <summary>
        /// 用户取消支付
        /// </summary>
        /// <param name="orderId">订单id</param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("PayFailed")]
        public PayFailedResponse PayFailed(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);

            var order = _ctx.ClinRecipeOrders.IsStatus(BillOrderExtensions.OrderStatus.支付中)
                .FirstOrDefault(x => x.WxUserId == azUser.UserId && x.Id == orderId);
            if (order == null)
            {
                return new PayFailedResponse
                {
                    ResultCode = "1",
                    ResultMsg = "订单不存在"
                };
            }

            order.OrderStatus = BillOrderExtensions.OrderStatus.支付失败.ToInt32();
            _ctx.SaveChanges();

            return new PayFailedResponse
            {
                ResultCode = "0",
                ResultMsg = ""
            };
        }

        /// <summary>
        /// 微信支付通知回调
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        [ActionName("PaySucceed")]
        public HttpResponseMessage PaySucceed()
        {
            var result = WeixinPayV3Helper.ParsePayNotify(Request.RequestUri, Request.Content.ReadAsStringAsync().Result.Copy());

            if (result.ResultCode == "0")//成功
            {
                var transactionId = result.PayOrder.TransactionId;
                lock (PayNotifyLocker)
                {
                    if (_ctx.WxPayNotifyLogs.Any(x => x.TransactionId == transactionId && x.TradeState == 0))
                    {
                        return new HttpResponseMessage
                        {
                            StatusCode = HttpStatusCode.OK,
                            Content = new StringContent(result.SuccessResponse)
                        };
                    }

                    //记录通过验证的支付通知
                    var orderNotifyLog = new WxPayNotifyLog
                    {
                        ServiceVersion = result.PayOrder.ServiceVersion,
                        Attach = result.PayOrder.Attach,
                        BankBillNo = result.PayOrder.BankBillNo,
                        BankType = result.PayOrder.BankType,
                        BuyerAlias = result.PayOrder.BuyerAlias,
                        Discount = result.PayOrder.Discount.ToNullableInt32(),
                        //FeeType = result.PayOrder.FeeType.ToNullableInt32(),
                        InputCharset = result.PayOrder.InputCharset,
                        NotifyId = result.PayOrder.NotifyId,
                        SignType = result.PayOrder.SignType,
                        Sign = result.PayOrder.Sign,
                        SignKeyIndex = result.PayOrder.SignKeyIndex.ToNullableInt32(),
                        //TradeMode = result.PayOrder.TradeMode.ToNullableInt32(),
                        TradeState = result.PayOrder.TradeState.ToNullableInt32(),
                        PayInfo = result.PayOrder.PayInfo,
                        Partner = result.PayOrder.Partner,
                        TotalFee = result.PayOrder.TotalFee.ToNullableInt32(),
                        TransactionId = result.PayOrder.TransactionId,
                        OutTradeNo = result.PayOrder.OutTradeNo,
                        TimerEnd = result.PayOrder.TimeEnd,
                        TransportFee = result.PayOrder.TransportFee.ToNullableInt32(),
                        ProductFee = result.PayOrder.ProductFee.ToNullableInt32(),
                        PostAppId = result.PayUser.AppId,
                        PostTimeStamp = result.PayUser.TimeStamp,
                        PostNonceStr = result.PayUser.NonceStr,
                        PostOpenId = result.PayUser.OpenId,
                        PostAppSignature = result.PayUser.AppSignature,
                        PostIsSubscribe = result.PayUser.IsSubscribe,
                        RecCreateDt = DateTime.Now,
                        Uri = Request.RequestUri.AbsoluteUri,
                        IsVerified = 1
                    };

                    _ctx.WxPayNotifyLogs.Add(orderNotifyLog);
                    _ctx.SaveChanges();


                    if (result.PayOrder.TradeState == "0")
                    {
                        //处理订单 并记录日志
                        if (result.PayOrder.OutTradeNo.StartsWith("BL"))
                        {
                            var orderNo = result.PayOrder.OutTradeNo.Substring(2);
                            var order = _ctx.ClinRecipeOrders.FirstOrDefault(x => x.OrderNo == orderNo);
                            if (order != null)
                            {
                                if (order.OrderStatus == BillOrderExtensions.OrderStatus.支付中.ToInt32())
                                {
                                    order.PayState = BillOrderExtensions.PayState.已付款.ToInt32().ToString();
                                    order.PayTime = DateTime.ParseExact(result.PayOrder.TimeEnd, "yyyyMMddHHmmss",
                                        CultureInfo.CurrentCulture);
                                    order.WxTransactionId = transactionId;
                                    order.OrderStatus = BillOrderExtensions.OrderStatus.支付成功.ToInt32();
                                    _ctx.SaveChanges();

                                    // RMQ 执行缴费操作
                                    var pickupingProducer = new OrderPickupingProducer();
                                    pickupingProducer.Publish(new OrderPickupingMsg
                                    {
                                        OrderType = Rmq.Center.OrderType.门诊缴费订单,
                                        OrderId = order.Id
                                    });
                                }
                                else if (order.OrderStatus == BillOrderExtensions.OrderStatus.缴费失败.ToInt32() ||
                                    order.OrderStatus == BillOrderExtensions.OrderStatus.支付失败.ToInt32())
                                {
                                    //His缴费失败，执行退款操作
                                    var refundingProducer = new OrderRefundingPickupFailedProducer();
                                    refundingProducer.Publish(new OrderRefundingPickupFailedMsg
                                    {
                                        OrderType = OrderType.门诊缴费订单,
                                        OrderId = order.Id
                                    });
                                }
                            }
                        }
                    }

                    return new HttpResponseMessage
                    {
                        StatusCode = HttpStatusCode.OK,
                        Content = new StringContent(result.SuccessResponse)
                    };
                }
            }
            #region 记录验证失败的支付通知

            var unverifiedNotifyLog = new WxPayNotifyLog
            {
                Uri = Request.RequestUri.AbsoluteUri,
                IsVerified = 0,
                RecCreateDt = DateTime.Now
            };
            _ctx.WxPayNotifyLogs.Add(unverifiedNotifyLog);
            _ctx.SaveChanges();

            #endregion

            return new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content = new StringContent(result.FailResponse)
            };
        }
 
        /// <summary>
        /// 查询缴费执行状态
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetBillStatus")]
        public GetBillStatusResponse GetBillStatus(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            var order = _ctx.ClinRecipeOrders.FirstOrDefault(x => x.Id == orderId && x.WxUserId == azUser.UserId);
            if (order == null)
            {
                return new GetBillStatusResponse
                {
                    ResultCode = "1",
                    ResultMsg = "订单不存在"
                };
            }

            if (order.OrderStatus == BillOrderExtensions.OrderStatus.缴费中.ToInt32()
                || order.OrderStatus == BillOrderExtensions.OrderStatus.支付中.ToInt32()
                || order.OrderStatus == BillOrderExtensions.OrderStatus.支付成功.ToInt32())
            {
                return new GetBillStatusResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    BillStatus = "2",
                    FailedMsg = ""
                };
            }

            if (order.OrderStatus == BillOrderExtensions.OrderStatus.缴费成功.ToInt32())
            {
                return new GetBillStatusResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    BillStatus = "0",
                    FailedMsg = ""
                };
            }

            return new GetBillStatusResponse
            {
                ResultCode = "0",
                ResultMsg = "",
                BillStatus = "1",
                FailedMsg = ""
            };
        }


        [HttpGet]
        [ActionName("GetBillOrderDetail")]
        public GetBillOrderDetailResponse GetBillOrderDetail(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            var order = _ctx.ClinRecipeOrders.FirstOrDefault(x => x.Id == orderId && x.WxUserId == azUser.UserId);
            if (order == null)
            {
                return new GetBillOrderDetailResponse
                {
                    ResultCode = "1",
                    ResultMsg = "订单不存在"
                };
            }

            var clinRecipeOrderItemList = _ctx.ClinRecipeOrderItems.Where(x => x.ClinRecipeOrderId == orderId).ToList();
            var isAllSelfPay = clinRecipeOrderItemList.All(x => x.PayType.IndexOf("自费", StringComparison.Ordinal) >= 0);

            var resultDatalist = _ctx.ClinRecipeResultDatas.Where(x => x.ClinRecipeId == orderId)
                .ToList()
                .Select(x => new GetBillOrderDetailResponse.ResultData
                {
                    FeeType = x.FeeType,
                    TotalAmt = x.TotalAmt.ToSingleOrDefault().ToString("F2") + " 元",
                    SelfAmt = x.SelfAmt.ToSingleOrDefault().ToString("F2") + " 元"
                }).ToList();

            return new GetBillOrderDetailResponse()
            {
                ResultCode = "0",
                ResultMsg = "",
                CardNo = order.CardNo,
                PatientName = order.PatName,
                HosPayId = order.HosPayId,
                InvoiceNo = order.InvoiceNo,
                TotalAmt = order.TotalAmt.ToSingleOrDefault().ToString("F2"),
                SelfAmt = order.SelfAmt.ToSingleOrDefault().ToString("F2"),
                SbPayAmt = order.SbPayAmt.ToSingleOrDefault().ToString("F2"),
                ResultMark = order.ResultMark,
                IsAllSelfPay = isAllSelfPay,
                ResultDatas = resultDatalist
            };
        }


        /// <summary>
        /// 获取缴费记录
        /// </summary>
        /// <param name="cardNo"></param>
        /// <param name="startDate"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetBillPayList")]
        public GetBillPayListResponse GetBillPayList(string cardNo, string startDate)
        {
            var request = new Request4GetClinPayList();
            request.HosPatId = "";
            request.ClinNo = "";
            request.IdCard = "";
            request.CardNo = cardNo;
            request.InvoiceNo = "";
            request.HosPayId = "";
            request.StartDate = startDate;
            request.EndDate = startDate.ToDateTimeOrDefault().AddDays(16).ToString("yyy-MM-dd"); ;

            Response4GetClinPayList response4GetClinPayList;
            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/GetClinPayList", request).Result;
                responseMsg.EnsureSuccessStatusCode();
                response4GetClinPayList = responseMsg.Content.ReadAsAsync<Response4GetClinPayList>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内GetClinPayList Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                return new GetBillPayListResponse
                {
                    ResultCode = "2",
                    ResultMsg = "服务器或网络异常，请联系客服"
                };
            }

            if (response4GetClinPayList.ResultCode != "0")
            {
                return new GetBillPayListResponse
                {
                    ResultCode = "2",
                    ResultMsg = response4GetClinPayList.ResultDesc
                };
            }

            var clinPayList = response4GetClinPayList.ClinPayList.Select(x => new GetBillPayListResponse.ClinPay()
            {
                HosPayId = x.HosPayId,
                PatName = x.PatName,
                PayType = x.PayType,
                TotalAmt = x.TotalAmt,
                SelfAmt = x.SelfAmt,
                SbPayAmt = x.SbPayAmt,
                PayDate = x.PayDate.ToDateTimeOrDefault().ToString("yyyy-MM-dd HH:mm:ss"),
                InvoiceNo = x.InvoiceNo,
                DeptName = x.DeptName,
                DoctorName = x.DoctorName
            }).OrderByDescending(x => x.PayDate).ToList();

            return new GetBillPayListResponse()
            {
                ResultCode = "0",
                ResultMsg = "",
                ClinPays = clinPayList
            };
        }

        /// <summary>
        /// 获取缴费明细
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetBillPayDetail")]
        public GetBillPayDetailResponse GetBillPayDetail(string hosPayId)
        {
            var request = new Request4GetClinPayDetail();
            request.HosPayId = hosPayId;

            Response4GetClinPayDetail response4GetClinPayDetail;
            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/GetClinPayDetail", request).Result;
                responseMsg.EnsureSuccessStatusCode();
                response4GetClinPayDetail = responseMsg.Content.ReadAsAsync<Response4GetClinPayDetail>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内GetClinPayDetail Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                return new GetBillPayDetailResponse
                {
                    ResultCode = "2",
                    ResultMsg = "服务器或网络异常，请联系客服"
                };
            }

            if (response4GetClinPayDetail.ResultCode != "0")
            {
                return new GetBillPayDetailResponse
                {
                    ResultCode = "2",
                    ResultMsg = response4GetClinPayDetail.ResultDesc
                };
            }

            var clinPayDetailList = response4GetClinPayDetail.ClinPayDetailList.Select(x =>
                new GetBillPayDetailResponse.ClinPayDetailInfo
                {
                    HosPayId = x.HosPayId,
                    RecipeId = x.RecipeId,
                    FeeName = x.FeeName,
                    FeeCode = x.FeeCode,
                    Unit = x.Unit,
                    Spec = x.Spec,
                    Price = x.Price,
                    Qty = x.Qty,
                    TotalAmt = x.TotalAmt,
                    SelfAmt = x.SelfAmt,
                    FeeType = x.FeeType,
                    Remark = x.Remark
                }).OrderByDescending(x => x.TotalAmt).ToList();

            return new GetBillPayDetailResponse()
            {
                ResultCode = "0",
                ResultMsg = "",
                ClinPayDetailInfos = clinPayDetailList
            };
        }

        /// <summary>
        /// 生成挂号订单号
        /// </summary>
        /// <returns></returns>
        public string GenerateNewOrderNo()
        {
            var orderNo = "WX" + DateTime.Now.Date.ToString("yyyyMMdd");
            lock (OrderNoLocker)
            {
                orderNo += (DateTime.Now - DateTime.Now.Date).TotalMilliseconds.ToString("00000000");
                Thread.Sleep(1);
            }

            return orderNo;
        }

        public string GetClientIp()
        {
            if (Request.Properties.ContainsKey("MS_HttpContext"))
            {
                string ip = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                //判断是否有代理服务器
                if (string.IsNullOrEmpty(ip))
                {
                    //没有代理服务器,如果有代理服务器获取的是代理服务器的IP
                    ip = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
                }

                string pattrn = @"(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])";
                if (!string.IsNullOrEmpty(ip) && System.Text.RegularExpressions.Regex.IsMatch(ip, pattrn))
                {
                    return ip;
                }

                return "127.0.0.1";
            }
            else
            {
                return "127.0.0.1";
            }
        }
    }
}
